
En la clase Visualización 1 vimos como realizar gráficos estáticos, es decir que no permiten analizarlos en forma dinámica, interactuando con ellos.
Python ofrece librerías que preparan los datos para una visualización donde el usuario sí puede interactuar.
Dos de las librerías más usadas actualmente son Bokeh y Plotly.
Bokeh, del japonés ぼけ (boke), significa 'desenfoque'. De un modo más gráfico y práctico se puede entender como la clásica imagen en la que el elemento principal es lo único que aparece enfocado y el resto de los elementos "desaparecen", totalmente desenfocados.
Para entender Bokeh, podemos compararlo con Matplotlib, ya que ambos generan gráficos, pero tienen un uso bastante diferente. Matplotlib crea gráficos estáticos útiles para una rápida y simple visualización. Bokeh crea visualizaciones para mostrar en la web, y son altamente interactivas.
Bokeh entonces es una librería de visualización interactiva. Proporciona una construcción concisa de gráficos en forma versátil, ofreciendo interactividad de alto rendimiento sobre grandes volúmenes de datos o streaming.
bokeh.plotting provee los elementos para crear los gráficos interactivos. Para usarlo adecuadamente, conviene seguir unos pasos básicos.
Preparar el dataset. Una simple lista, tipos de datos de Numpy y Pandas.
Informar donde se genera la salida del gráfico.
Se usa generalmente las funciones: output_file: genera archivos html para las visualizaciones Bokeh. output_notebook: las muestra como celdas de jupyter notebooks. Se debe realizar solo una vez salvo que se quiere modificar posteriormente la salida.
Llamar a la función figure(). Similar a Matplotlib, es el contenedor donde se definen el estilo general, los títulos, grillas, labels de los ejes y además los tools (la barra con los botones para actuar en forma interactiva).
Agregar los Glyphs (glifos). El término glyph en Bokeh se refiere a los puntos, líneas, áreas y otras figuras geométricas que representan a los datos.
Estos dos últimos pasos los podemos repetir para mostrar varios gráficos juntos.
Informar a Bokeh como mostramos los resultados. show() muestra en el browser el gráfico. save() lo graba en el file definido anteriormente.
from bokeh.plotting import figure, output_notebook, show
from bokeh.io import output_notebook
from bokeh.resources import INLINE
# Dataset
circle_x = [1, 2.5, 3, 2]; circle_y = [2, 3, 1, 1.5]
triangle_x = [1, 3, 2]; triangle_y = [3, 1, 1.5]
# Salida del gráfico
output_notebook(INLINE)
# Figure
p = figure(plot_width=250, plot_height=150, tools="pan,reset,save")
# Glyphs
p.triangle(x=triangle_x, y=triangle_y, color='red', size=20)
p.circle(x=circle_x, y=circle_y, radius=0.3, alpha=0.5)
show(p) # Mostrar los resultados
Bokeh ofrece datasets de ejemplo, que se pueden bajar en C:\Users\xxxxx.bokeh\data (Windows):
import bokeh.sampledata
bokeh.sampledata.download()
También se puede importar:
from bokeh.sampledata.gapminder import fertility, life_expectancy, population, regions
anios = ['1970','1980','1990','2000','2010']
s_argentina = life_expectancy.loc['Argentina',anios]
s_zambia = life_expectancy.loc['Zambia',anios]
s_suecia = life_expectancy.loc['Sweden',anios]
s_china = life_expectancy.loc['China',anios]
s_usa = life_expectancy.loc['United States',anios]
life_expectancy.sample(2)
| 1964 | 1965 | 1966 | 1967 | 1968 | 1969 | 1970 | 1971 | 1972 | 1973 | ... | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Country | |||||||||||||||||||||
| Nigeria | 38.906 | 39.287 | 39.657 | 34.000 | 29.000 | 27.000 | 37.000 | 41.610 | 42.047 | 42.495 | ... | 48.132 | 48.671 | 49.236 | 49.799 | 50.337 | 50.839 | 51.297 | 51.717 | 52.116 | 52.506 |
| Armenia | 67.714 | 68.151 | 68.587 | 69.015 | 69.425 | 69.808 | 70.143 | 70.411 | 70.604 | 70.722 | ... | 73.192 | 73.491 | 73.730 | 73.920 | 74.070 | 74.191 | 74.291 | 74.381 | 74.469 | 74.561 |
2 rows × 50 columns
En este ejemplo, en Figure agregamos el título, etiquetas de los ejes, el tamaño del gráfico.
Además con el parámetro tools se describen las acciones interactivas permitidas. Se agrupan por:
drag tools (arrastrando el mouse). Por ejemplo, box_select (un rectángulo); (selecciona rectángulo donde hacer zoom); lasso_select (con un lazo), pan (genera una panorámica, sosteniendo el click y moviendo el mouse).
click tools (con un click). tap (selecciona un punto), entre otros.
scroll tools (scrolling). wheel_zoom (zoom con la ruedita del mouse),box_zoom.
Acciones. reset (vuelve a los valores originales); save (graba el gráfico como un archivo PNG)
# Dataset
anios = ['1970','1980','1990','2000','2010']
output_notebook(INLINE)
# Figure
fig = figure(title="Expectativa de vida", x_axis_label='Años',y_axis_label='Años de vida',
tools="box_select,box_zoom,lasso_select,tap,wheel_zoom,pan,reset,save",
toolbar_location="above", plot_width=400, plot_height=250)
# Tres Glyphs.
fig.circle(x=anios, y=s_argentina, color='red', size=4)
fig.triangle(x=anios, y=s_suecia, color='aquamarine', size=8)
fig.circle_x(x=anios, y=s_zambia, size=10, alpha=0.5)
show(fig) # Mostrar los resultados
Bokeh provee una colección de paletas predefinidas que podemos ver en
https://docs.bokeh.org/en/latest/docs/reference/palettes.html
Useremos colores de Set2 para colorear las barras del siguiente gráfico. Observar que tenemos que informar cuantos colores vamos a usar. En este ejemplo, son cinco.
from bokeh.palettes import Set2
colors = Set2[5]
colors[1]
'#fc8d62'
Se grafican tanto barras verticales, como horizontales. Y también barras apiladas.
Para las barras verticales vbar() necesitamos el rango de valores para el eje x x=, los valores del eje y que se indican con top=. También se puede agregar un valor bottom=. El proceso es similar para las barras horizontales.
En el proximo ejemplo vamos a generar barras de varias variables. Como en Matplotlib, luego de definir la primera barra, las siguientes deben tener un offset para que no se superpongan.
Para que la leyenda con los nombres de los países quede afuera del gráfico, usamos el método p.add_layout.
Nota: se debe agregar en la función Figure, el parámetro x_range=anios para que admita valores categóricos en el eje x.
import numpy as np
from bokeh.models import Legend
p = figure(x_range=anios, plot_width=600, plot_height=230
, title='Comparacion de paises', x_axis_label='Años',y_axis_label='Años de vida')
r0 = p.vbar(x=anios, top=s_zambia, width=0.1, bottom=0, color=colors[0])
offsets = [0.1, 0.1, 0.1, 0.1, 0.1]
anios_off = list(zip(anios, offsets))
r1 = p.vbar(x=anios_off, top=s_suecia, width=0.1, bottom=0, color=colors[1])
anios_off = list(zip(anios, np.array(offsets)*2))
r2 = p.vbar(x=anios_off, top=s_argentina, width=0.1, bottom=0, color=colors[2])
anios_off = list(zip(anios, np.array(offsets)*3))
r3 = p.vbar(x=anios_off, top=s_usa, width=0.1, bottom=0, color=colors[3])
anios_off = list(zip(anios, np.array(offsets)*4))
r4 = p.vbar(x=anios_off, top=s_china, width=0.1, bottom=0, color=colors[4])
legend = Legend(items=[("Zambia", [r0]), ("Suecia", [r1]), ("Argentina", [r2]),
("USA", [r3]), ("China", [r4])], location="center")
p.add_layout(legend, 'right')
show(p)
Las áreas se grafican pintando la región entre dos series que compartan un eje x o índice común.
En el ejemplo, dibujamos el área bajo la curva de los Estados Unidos.
output_notebook(INLINE)
# Figure
fig = figure(title = "Expectativa de vida", x_axis_label = 'Años', y_axis_label = 'Años de vida',
tools = "pan,reset,save,wheel_zoom", toolbar_location = "below",
x_range = anios, plot_width = 400, plot_height = 250)
# Area
fig.varea(x = anios, y1 = 0, y2 = s_usa , fill_color = 'blueviolet', alpha = 0.3);
show(fig)
Se pueden graficar rectángulos, elipses y polígonos con Bokeh.
rect() y square() generan rectángulos y cuadrados basado en las coordenadas del centro de la figura. Las dimensiones, rect() las define con el ancho y largo y square() con el parámetro size.
ellipse() crea glyphs con las coordenadas x, y, y el ancho y el largo.
# Salida del gráfico
output_notebook(INLINE)
# Figure
fig = figure(plot_width=300, plot_height=150)
# Glyphs
fig.rect(x=10,y=10,width=100, height=50, color='green',width_units='screen', height_units='screen')
fig.square(x=2,y=3,size=80, color='red')
fig.ellipse(x=7,y=6, width=30, height=10, fill_color=None, line_width=2)
fig.ellipse(x=15,y=6,width=2, height=1, angle=-0.4)
show(fig)
ColumnDataSource es muy usado en los gráficos de Bokeh; permite fácilmente compartir datos entre múltiples gráficos.
Cuando se utiliza el mismo objeto ColumnDataSource como origen de datos de múltiples gráficos, la selección del origen de datos también se comparte. Es decir, que con una herramienta de selección aplicada en un gráfico, se reflejan los puntos seleccionados en los otros gráficos.
gridplot crea una grilla de plots, y construye una única toolbar compartida entre todos los plots de la grilla.
Observar que cada gráfico debe tener su Figure y su glyph; luego se unen con gridplot.
from bokeh.models import ColumnDataSource
from bokeh.layouts import gridplot
# datos de autos
from bokeh.sampledata.autompg import autompg as data_cars
data_bokeh = ColumnDataSource(data_cars)
options = {'plot_width': 300,'plot_height': 150,'tools': 'pan, box_select, lasso_select, reset'}
p1 = figure(title="MPG por Año", x_axis_label = "MPG", y_axis_label = "Año", **options)
p1.circle("yr", "mpg", color = "blue", source = data_bokeh)
p2 = figure(title="HP vs. Desplazamiento", x_axis_label = "HP",y_axis_label = "Desp", **options)
p2.cross("hp", "displ", color = "green", source = data_bokeh)
p3 = figure(title="MPG vs. Desplazamiento", x_axis_label = "MPG", y_axis_label = "Desp", **options)
p3.diamond("mpg", "displ", size = "cyl", line_color="red", fill_color = None
, source = data_bokeh)
p4 = figure(title="Aceleración vs. Desplazamiento", x_axis_label = "Aceleración", y_axis_label = "Desp", **options)
p4.triangle("accel", "displ", color = "yellow", source = data_bokeh)
p = gridplot([[p1, p2], [p3, p4]] , toolbar_location="right")
show(p)
Es una herramienta de inspección pasiva, que permite asociar a cada dato que se visualiza en el gráfico, con una tabla de valores que lo complementa. En el próximo ejemplo, cuando pasemos el mouse por un círculo, veremos una tabla con las coordenadas de ese punto y una descripción.
La función Hovertool nos permite crearlo. Podemos asociar un etiqueta a cada dato:
hover = HoverTool(tooltips=[("index", "$index"), ("(x,y)", "($x, $y)"),("desc", "@desc")])
Las etiquetas y los valores se asignan en una lista de tuplas (etiqueta, valor).
Los nombres de campo que comienzan con '$' son "campos especiales". A menudo son valores intrínsecos del gráfico, como las coordenadas del mouse en pantalla. Ejemplos:
$index: indíce del punto seleccionado en el dataset. Un ID.$x: coordenada x del cursor en el espacio de datos$y: coordenada y del cursor en el espacio de datosLos nombres de campo que comienzan con '@' están asociados con columnas definidas en ColumnDataSource.
from bokeh.plotting import ColumnDataSource, figure, output_file, show
from bokeh.models import HoverTool
output_notebook(INLINE)
# Dataset
source = ColumnDataSource(data=dict(
x=[1, 2, 3, 4, 5],
y=[2, 5, 8, 2, 7],
desc=['A', 'b', 'C', 'd', 'E'],
))
# Figure
p = figure(plot_width=400, plot_height=200, tools = ['pan', 'box_zoom', 'reset'],title="Mouse over the dots")
p.circle('x', 'y', size=20, source=source,hover_color="pink", hover_alpha=0.6)
# Tooltips indica que valores muestra al pasar el mouse por los puntos
hover = HoverTool(tooltips=[("index", "$index"), ("(x,y)", "($x, $y)"),("desc", "@desc")])
p.add_tools(hover)
show(p)
Bokeh también permite guardar plots en archivos HTML. Para eso usamos la función output_file y save, en lugar de output_notebook() y show.
También podemos usar la combinación output_file y show que abre en una nueva pestaña el gráfico guardado.
Guardemos el último gráfico generado, que está asignado a la variable p
from bokeh.plotting import output_file, save
output_file("test_save_plot.html", mode='inline')
save(p);
Para resetear los settings de output usamos reset_output
from bokeh.plotting import reset_output
reset_output()
Plotly es una librería de Python que genera gráficos interactivos de una manera sencilla.
Basicámente podemos crear todos los gráficos que vimos hasta ahora: diagramas de líneas, de barras, de áreas, histogramas, etc, y otros como diagrama de burbujas. Ademas de disponer de una grilla de gráficos, hovertool y animaciones.
Se pueden mostrar usando Jupyter notebooks, grabarlos como archivos html, y también en una aplicación Web usando la librería Dash.
Tiene una versión web, que permite publicar los gráficos. Esa versión online se trabaja con el paquete chart-studio. No forma parte de esta clase.
Plotly Express es una función de Plotly con una interfaz de alto nivel. Opera sobre una variedad de tipos de datos y genera figuras fáciles de trabajar en su estilo.
Todos los gráficos de esta clase los vamos a generar usando Plotly Express.
Las funciones de Plotly Express devuelven un objeto de tipo graph_objects.Figure cuyos datos y layout se definen de acuerdo a los argumentos provistos. Y que se muestra en la notebook con el método show. Con write_image se graba en un archivo.
El esquema general para crear gráficos es:
fig = px.chart_type(df, parameters) (chart_type: bar, scatter, etc. df: dataframe)
fig.update_layout(layout_parameters or add annotations)
fig.update_traces(further graph parameters)
fig.update_xaxis() # or update_yaxis
fig.show()
import numpy as np
import pandas as pd
import plotly.express as px
import plotly as pl
pl.offline.init_notebook_mode(connected=True)
Por ejemplo:
fig = px.bar(x=['DS', 'DE', 'SE'], y=[20, 14, 23] ,width=400, height=250)
fig.update_layout(title='sample figure')
fig.update_traces(marker_color='red', width=0.1)
fig.update_xaxes(title='Profesiones')
fig.update_yaxes(title='Total Salario',titlefont_size=8,tickfont_size=14)
fig.show()
fig.write_image("fig1_offline.png")
Con px.bar, cada fila de un Dataframe se representa con una barra.
Podemos hacer diagramas de barras (bar), barras apiladas (stacked bar), y agrupadas por una variable categórica.
En este ejemplo, a partir del Dataframe df_tips, usamos las variables categóricas sex y time (en qué momento del día), para clasificar las barras por el total de propinas recibidas.
df_tips = px.data.tips()
df_tips.sample(3)
| total_bill | tip | sex | smoker | day | time | size | |
|---|---|---|---|---|---|---|---|
| 46 | 22.23 | 5.00 | Male | No | Sun | Dinner | 2 |
| 37 | 16.93 | 3.07 | Female | No | Sat | Dinner | 3 |
| 201 | 12.74 | 2.01 | Female | Yes | Thur | Lunch | 2 |
Con px.bar definimos los datos y ajustes generales. Con el parámetro color indicamos la tercera variable.
Con el método update_layout incorporamos otra información de estilo.
Pasando el mouse, observamos los valores de cada fila.
df_tips = px.data.tips() # Dataset de propinas
fig = px.bar(data_frame=df_tips, x="sex", y="total_bill", color='time', width=400, height=250)
fig.update_layout(
title='Propinas por sexo y tiempo',
xaxis_tickfont_size=10,
yaxis=dict(title='Total Propinas',titlefont_size=14,tickfont_size=10))
fig.show()
Bubble chart o diagrama de burbujas, es simplemente un diagrama scatter o de dispersión, donde el tamaño de cada punto representa el valor de una columna del dataframe.
Lo representamos con el parámetro size.
En este ejemplo, tenemos datos sobre la expectativa de vida (lifeExp), el producto interno bruto per cápita (gdpPercap) y la población (pop), por año, continente y país.
La burbuja o tamaño de cada punto, representa el valor de la variable pop.
data_gap = pd.read_csv('../Data/gapminderDataFiveYear.txt', sep='\t')
data_gap.sample(5)
| country | year | pop | continent | lifeExp | gdpPercap | |
|---|---|---|---|---|---|---|
| 276 | Chile | 1952 | 6377619.0 | Americas | 54.745 | 3939.978789 |
| 1466 | Sweden | 1962 | 7561588.0 | Europe | 73.370 | 12329.441920 |
| 826 | Kenya | 2002 | 31386842.0 | Africa | 50.992 | 1287.514732 |
| 1099 | New Zealand | 1987 | 3317166.0 | Oceania | 74.320 | 19007.191290 |
| 1569 | Tunisia | 1997 | 9231669.0 | Africa | 71.973 | 4876.798614 |
Creamos un gráfico con los siguientes lineamientos:
Scatter plot de expectativa de vida (lifeExp) versus PIB per cápita (gdpPercap), para el año 2007, para todos los países.
El tamaño de los marcadores (burbujas) es creciente en función del tamaño de la población (pop).
Cada continente (continent) se representa con un color distinto.
El texto que se muestra al pasar el mouse, hover, tiene que tener como título el país (country).
Creamos una barra para seleccionar el rango del eje x que queremos ver fig.update_xaxes(rangeslider_visible=True)
# El año 2007 para todos los países
data_year_mask = data_gap['year'] == 2007
data_year = data_gap.loc[data_year_mask, :]
data_year.head(3)
| country | year | pop | continent | lifeExp | gdpPercap | |
|---|---|---|---|---|---|---|
| 11 | Afghanistan | 2007 | 31889923.0 | Asia | 43.828 | 974.580338 |
| 23 | Albania | 2007 | 3600523.0 | Europe | 76.423 | 5937.029526 |
| 35 | Algeria | 2007 | 33333216.0 | Africa | 72.301 | 6223.367465 |
fig = px.scatter(data_frame = data_year, x = "gdpPercap", y = "lifeExp",
size = "pop", color = "continent", opacity = 0.6,
hover_name="country", width=700, height=500)
fig.update_xaxes(rangeslider_visible=True)
fig.show()
Facet es la facilidad que brinda Plotly para generar múltiple gráficos vinculados, similar a gridplot en Bokeh.
El valor del argumento facet_col (o facet_row) crea los gráficos vinculados, donde las distintas columnas de la grilla de gráficos corresponden a los diferentes valores de la columna indicada por el argumento.
El valor de facet_col_wrap indica el máximo número de columnas que tendrá el gráfico.
En este ejemplo, la columna year indica que cada columna de la grilla corresponde a un año.
fig = px.scatter(data_gap, x = 'gdpPercap', y = 'lifeExp', color = 'continent', size = 'pop',
facet_col = 'year', facet_col_wrap = 3)
fig.show()
Las animaciones son gráficos que muestran un "movimiento" de acuerdo a los valores de alguna columna.
El valor del argumento animation_frame indica la columna sobre la cual el gráfico evoluciona, o dicho de otra forma, el que define cada cuadro (frame) de la animación. Generalmente es una variable de tiempo.
El valor del argumento animation_group indica la columna que provee la consistencia entre los frames; los registros que coinciden en el valor de animation_group representan el mismo objeto en todos los frames. En el ejemplo, la columna country indica que todos los registros de un país se consideran relacionados en todos los frames.
range_x y range_y definen el rango de valores de los ejes x e y respectivamente. Si el valor del argumento log_x (log_y) es True, la escala del eje x (eje y) es logarítmica. Los rangos deben asegurar que todos los datos sean visibles, que no salgan de los rangos.
Generemos ahora una animación sobre los años usando como base el bubble chart que generamos anteriormente.
fig = px.scatter(data_gap,
x = "gdpPercap", y = "lifeExp",
animation_frame = "year", animation_group = "country",
size = "pop", color = "continent", hover_name="country",
log_x=True, size_max=55, range_x=[100,100000], range_y=[25,90])
fig.show()
A partir de los datos de los autos que vimos anteriormente, generar un gráfico de barras vbar que muestre la cantidad de autos por año.
Las barras deben medir 0.1 y tienen que tener el color rojo.
Ayuda:
se debe usar groupby.
df_autos_anio = data_cars.groupby("xxx")["yyy"].count()
df_autos_anio es una Pandas Serie, no un DataFrame.
# datos de autos
from bokeh.sampledata.autompg import autompg as data_cars
data_cars.sample(3)
| mpg | cyl | displ | hp | weight | accel | yr | origin | name | |
|---|---|---|---|---|---|---|---|---|---|
| 305 | 26.8 | 6 | 173.0 | 115 | 2700 | 12.9 | 79 | 1 | oldsmobile omega brougham |
| 291 | 31.9 | 4 | 89.0 | 71 | 1925 | 14.0 | 79 | 2 | vw rabbit custom |
| 294 | 27.4 | 4 | 121.0 | 80 | 2670 | 15.0 | 79 | 1 | amc spirit dl |
Hacer el ejercicio anterior con Plotly.
A partir de los datos de los autos que vimos anteriormente, generar un gráfico de barras que muestre la cantidad de autos por año.
Las barras deben medir 0.1 y tienen que tener el color rojo.
Ayuda:
se debe usar groupby.
df_autos_anio = data_cars.groupby("xxx")["yyy"].count()
df_autos_anio es una Pandas Serie, no un DataFrame.
A partir de los datos de los autos que vimos anteriormente, generar un gráfico de barras vbar que muestre la cantidad de autos por año.
Las barras deben medir 0.1 y tienen que tener el color rojo.
Ayuda:
se debe usar groupby.
df_autos_anio = data_cars.groupby("xxx")["yyy"].count()
df_autos_anio es una Pandas Serie, no un DataFrame.
# datos de autos
from bokeh.sampledata.autompg import autompg as data_cars
data_cars.sample(3)
| mpg | cyl | displ | hp | weight | accel | yr | origin | name | |
|---|---|---|---|---|---|---|---|---|---|
| 319 | 32.2 | 4 | 108.0 | 75 | 2265 | 15.2 | 80 | 3 | toyota corolla |
| 324 | 43.4 | 4 | 90.0 | 48 | 2335 | 23.7 | 80 | 2 | vw dasher (diesel) |
| 237 | 30.0 | 4 | 97.0 | 67 | 1985 | 16.4 | 77 | 3 | subaru dl |
df_autos_anio = data_cars.groupby("yr")["name"].count()
type(df_autos_anio)
pandas.core.series.Series
df_autos_anio.head(3)
yr 70 29 71 27 72 28 Name: name, dtype: int64
df_autos_anio.index
Int64Index([70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82], dtype='int64', name='yr')
output_notebook(INLINE)
options = {'plot_width': 500,'plot_height': 300,'tools': 'pan, box_select, lasso_select, reset'}
p = figure(title="Autos por Año", x_axis_label = "Años", y_axis_label = "Total Autos", **options)
p.vbar(x=df_autos_anio.index, top=df_autos_anio, color = "red",width=0.1)
show(p)
Hacer el ejercicio anterior con Plotly.
A partir de los datos de los autos que vimos anteriormente, generar un gráfico de barras que muestre la cantidad de autos por año.
Las barras deben medir 0.1 y tienen que tener el color rojo.
Ayuda:
se debe usar groupby.
df_autos_anio = data_cars.groupby("xxx")["yyy"].count()
df_autos_anio es una Pandas Serie, no un DataFrame.
df_autos_anio.head(3)
yr 70 29 71 27 72 28 Name: name, dtype: int64
fig = px.bar(x=df_autos_anio.index, y=df_autos_anio, width=600, height=400)
fig.update_layout(
title='Autos por Año',
xaxis_tickfont_size=10,
xaxis=dict(title='Años',titlefont_size=14,tickfont_size=10),
yaxis=dict(title='Total Autos',titlefont_size=14,tickfont_size=10))
fig.update_traces(marker_color='red', width=0.1)
fig.show()